﻿//-----------------------------------------------------------------------
// <copyright file="FCISPlusServer.cs" company="FCIS">
//     Company copyright tag.
// </copyright>
// <author>Ramy Medhat</author>
// <date>24/8/2011</date>
// <reviewer></reviewer>
//-----------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FCISPlus.Server.Database;

namespace FCISPlus.Server.Backend
{
    /// <summary>
    /// FCIS+ Server
    /// </summary>
    internal class FCISPlusServer
    {
        /// <summary>
        /// Database context.
        /// </summary>
        private Database.FCISPlusDBDataContext context;

        /// <summary>
        /// Initializes a new instance of the <see cref="FCISPlusServer"/> class.
        /// </summary>
        public FCISPlusServer()
        {
            this.context = new FCISPlusDBDataContext();
        }

        /// <summary>
        /// Gets the context.
        /// </summary>
        public FCISPlusDBDataContext Context
        {
            get { return this.context; }
        }

        #region IFCISPlusServer Members

        /// <summary>
        /// Checks the login.
        /// </summary>
        /// <param name="username">The username.</param>
        /// <param name="password">The password.</param>
        /// <returns>
        /// Boolean indicating the success of login.
        /// </returns>
        public bool CheckLogin(string username, string password)
        {
            User[] users = this.context.Users.Where(u => u.Username == username && u.Password == password).ToArray();

            if (users.Length == 0)
            {
                return false;
            }

            return true;
        }

        /// <summary>
        /// Gets the user.
        /// </summary>
        /// <param name="username">The username.</param>
        /// <returns>
        /// Gets the user object.
        /// </returns>
        public User GetUser(string username)
        {
            User[] users = this.context.Users.Where(u => u.Username == username).ToArray();

            if (users.Count() != 1)
            {
                throw new Exception();
            }

            return users[0];
        }

        /// <summary>
        /// Creates the user.
        /// </summary>
        /// <param name="username">The username.</param>
        /// <param name="password">The password.</param>
        /// <returns>
        /// The created user object.
        /// </returns>
        public User CreateUser(string username, string password)
        {
            try
            {
                User user = new User();
                user.Username = username;
                user.Password = password;

                this.context.Users.InsertOnSubmit(user);
                this.context.SubmitChanges();

                return user;
            }
            catch
            {
                return null;
            }
        }

        /// <summary>
        /// Updates the profile.
        /// </summary>
        /// <param name="user">The user.</param>
        /// <param name="age">The age.</param>
        /// <param name="interests">The interests.</param>
        public void UpdateProfile(User user, int age, string interests)
        {
            user.Age = age;
            user.Interests = interests;

            this.context.SubmitChanges();
        }

        /// <summary>
        /// Gets the friends.
        /// </summary>
        /// <param name="user">The user.</param>
        /// <returns>
        /// Array of friends.
        /// </returns>
        public Database.User[] GetFriends(Database.User user)
        {
            return context.ExecuteQuery<User>(@"select * from Users where Users.UserID in
                    ( select Friends.FriendID from Friends where Friends.UserID = {0} )", new object[] { user.UserID }).ToArray();
        }


        /// <summary>
        /// Adds the friend to user.
        /// </summary>
        /// <param name="user">The user.</param>
        /// <param name="friend">The friend.</param>
        public void AddFriendToUser(Database.User user, Database.User friend)
        {
            
            Friend friendship = new Friend()
                {
                    UserID = user.UserID,
                    FriendID = friend.UserID
                };

            if (this.context.Friends.Contains(friendship)) return;

            this.context.Friends.InsertOnSubmit(friendship);            

            this.context.SubmitChanges();
        }

        /// <summary>
        /// Removes a friend from user.
        /// </summary>
        /// <param name="user">The user.</param>
        /// <param name="friend">The friend.</param>
        public void RemoveFriendFromUser(Database.User user, Database.User friend)
        {
            Friend[] friendObject = this.context.Friends.Where(f => f.UserID == user.UserID && f.FriendID == friend.UserID).ToArray();
            
            if (friendObject.Length != 1)
            {
                throw new Exception();
            }

            this.context.Friends.DeleteOnSubmit(friendObject[0]);
            this.context.SubmitChanges();
        }

        /// <summary>
        /// Gets all users.
        /// </summary>
        /// <returns>List of Users</returns>
        public Database.User[] GetAllUsers()
        {
            return this.context.Users.ToArray();
        }

        /// <summary>
        /// Gets the user feeds.
        /// </summary>
        /// <param name="user">The user.</param>
        /// <returns>
        /// Array of posts.
        /// </returns>
        public Database.Post[] GetUserFeeds(Database.User user)
        {
            List<Post> allPosts = new List<Post>();

            allPosts.AddRange(from p in context.Posts where p.UserID == user.UserID select p);

            foreach (User friend in GetFriends(user))
            {
                allPosts.AddRange(from p in context.Posts where p.UserID == friend.UserID select p);
            }

            return allPosts.OrderBy(x => x.PostDate).Reverse().ToArray();
        }

        /// <summary>
        /// Adds a post.
        /// </summary>
        /// <param name="user">The user.</param>
        /// <param name="postText">The post text.</param>
        /// <param name="postLink">The post link.</param>
        public void AddPost(Database.User user, string postText, string postLink)
        {
            Post post = new Post()
            {
                PostText = postText,
                PostLink = postLink,
                PostDate = DateTime.Now,
                User = user
            };

            this.context.Posts.InsertOnSubmit(post);
            this.context.SubmitChanges();
        }

        /// <summary>
        /// Adds a comment.
        /// </summary>
        /// <param name="user">The user.</param>
        /// <param name="post">The post.</param>
        /// <param name="comment">The comment.</param>
        public void AddComment(Database.User user, Database.Post post, string comment)
        {
            Comment newComment = new Comment()
            {
                CommentText = comment,
                CommentDate = DateTime.Now,
                Post = post,
                User = user
            };

            this.context.Comments.InsertOnSubmit(newComment);
            this.context.SubmitChanges();
        }

        /// <summary>
        /// Likes the specified post.
        /// </summary>
        /// <param name="user">The user.</param>
        /// <param name="post">The post.</param>
        public void Like(Database.User user, Database.Post post)
        {
            Like like = new Like()
            {
                Post = post,
                User = user
            };

            this.context.Likes.InsertOnSubmit(like);
            this.context.SubmitChanges();
        }

        /// <summary>
        /// Unlikes the specified post.
        /// </summary>
        /// <param name="user">The user.</param>
        /// <param name="post">The post.</param>
        public void Unlike(Database.User user, Database.Post post)
        {
            Like[] likes = this.context.Likes.Where(x => x.User == user && x.Post == post).ToArray();

            if (likes.Count() != 1)
            {
                throw new Exception();
            }

            this.context.Likes.DeleteOnSubmit(likes[0]);
            this.context.SubmitChanges();
        }

        /// <summary>
        /// Sends the message.
        /// </summary>
        /// <param name="user">The user.</param>
        /// <param name="friend">The friend.</param>
        /// <param name="messageText">The message text.</param>
        public void SendMessage(User user,User friend, string messageText)
        {
            Message newMessage = new Message()
            {                
                MessageText = messageText,              
                MessageDate = DateTime.Now,
                User = user,
                User1 = friend
            };
            this.context.Messages.InsertOnSubmit(newMessage);
            this.context.SubmitChanges();
        }

        /// <summary>
        /// Gets the recent conversations.
        /// </summary>
        /// <param name="user">The user.</param>
        /// <param name="messageLifeTime">The message life time.</param>
        /// <returns>Array of messages.</returns>
        public Message[] GetRecentConversations(User user, TimeSpan messageLifeTime)
        {
            return context.ExecuteQuery<Message>(@"Select TOP 1 * from Messages inner join 
            (
            Select MAX(MessageDate) as MessageDate, FromUserID
            from Messages
            where ToUserID={0}
            Group By FromUserID
            )t
            on t.FromUserID= Messages.FromUserID
            and t.MessageDate=Messages.MessageDate
            Where 
            ToUserID={0}", new object[] { user.UserID }).ToArray();
        }

        /// <summary>
        /// Gets the conversation by friend.
        /// </summary>
        /// <param name="user">The user.</param>
        /// <param name="friend">The friend.</param>
        /// <param name="messageLifeTime">The message life time.</param>
        /// <returns></returns>
        public Message[] GetConversationByFriend(User user, User friend, TimeSpan messageLifeTime)
        {
            DateTime messageMinDate = DateTime.Now.Subtract(messageLifeTime);
            Message[] messages = this.context.Messages.
                Where(x => (x.User == user || x.User1 == user) && (x.User == friend || x.User1 == friend) && x.MessageDate >= messageMinDate).
                OrderByDescending(y => y.MessageDate).ToArray();
            return messages;
        }

        #endregion
    }
}
